/**
 * @author Fabien Bizot
 */
package com.lafabrick.components
{
	import com.lafabrick.util.CursorUtil;
	
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import mx.core.Application;
	
	[IconFile("ResizableWindowIcon.png")]
	
	/**
	 * Evénement déclenché lorsque l'utilisateur démarre le resize du composant
	 */
	[Event(name="startResizing", type="mx.events.Event")]
	
	/**
	 * Evénement déclenché lorsque l'utilisateur stop le resize
	 */
	[Event(name="stopResizing", type="mx.events.Event")]
	
	/**
	 * Evénement déclenché lorsque l'utilisateur resize le composant
	 */
	[Event(name="isResizing", type="mx.events.Event")]
	
	/**
	 * Définit la skin du curseur pour le redimensionnement oblique à gauche.
	 */
	
	[Style(name="cursorLeftObliqueSkin", type="Class", inherit="no")]
	/**
	 * Définit la skin du curseur pour le redimensionnement oblique à droite.
	 */
	[Style(name="cursorRightObliqueSkin", type="Class", inherit="no")]
	
	/**
	 * Définit la skin du curseur pour le redimensionnement vertical.
	 */
	[Style(name="cursorVerticalSkin", type="Class", inherit="no")]
	
	/**
	 * Définit la skin du curseur pour le redimensionnement horizontal.
	 */
	[Style(name="cursorHorizontalSkin", type="Class", inherit="no")]
	
	/**
	 * Composant étendu de DraggableWindow. 
	 * Ajout des fonctionnalitées Resize.
	 */
	public class ResizableWindow extends DraggableWindow
	{
		
		[Embed(source="../assets/cursor/leftObliqueCursor.gif")]
		private static var LEFT_OBLIQUE_CURSOR:Class;
		
		[Embed(source="../assets/cursor/rightObliqueCursor.gif")]
		private static var RIGHT_OBLIQUE_CURSOR:Class;
		
		[Embed(source="../assets/cursor/horizontalCursor.gif")]
		private static var HORIZONTAL_CURSOR:Class;
		
		[Embed(source="../assets/cursor/verticalCursor.gif")]
		private static var VERTICAL_CURSOR:Class;
		
		/**
		 * @private
		 */
		public static const SIDE_OTHER:Number = 0;
		/**
		 * @private
		 */
		public static const SIDE_TOP:Number = 1;
		/**
		 * @private
		 */
		public static const SIDE_BOTTOM:Number = 2;
		/**
		 * @private
		 */
		public static const SIDE_LEFT:Number = 4;
		/**
		 * @private
		 */
		public static const SIDE_RIGHT:Number = 8;
		
		private var _windowMinWidth:Number = 50;
		private var _windowMinHeight:Number = 50;
		
		private var _resizeEnabled:Boolean = false;
		private static var resizeObj:Object;
		private static var mouseState:Number = 0;
		private static var mouseMargin:Number = 10;
		private var oWidth:Number = 0;
		private var oHeight:Number = 0;
		private var oX:Number = 0;
		private var oY:Number = 0;
		private var oPoint:Point = new Point();
		
		/**
		 * Constructeur
		 */
		public function ResizableWindow() 
		{
			super();
			initPosition(this);
			
			this.addEventListener(MouseEvent.MOUSE_MOVE, oMouseMove);
			this.addEventListener(MouseEvent.MOUSE_OUT, oMouseOut);
			this.addEventListener(MouseEvent.MOUSE_DOWN, oMouseDown);
			
			Application.application.parent.addEventListener(MouseEvent.MOUSE_UP, oMouseUp);
			Application.application.parent.addEventListener(MouseEvent.MOUSE_MOVE, oResize);
		}
		
		
		[Inspectable(defaultValue=50, verbose=1, category="Expanded Properties")]
		public function set windowMinWidth(value:Number):void{
            this._windowMinWidth = value;         
        }
        /**
		 * Définit la largeur minimal de la fenêtre au redimensionnement.
		 * @param value:Number Largeur mini de la fenêtre.
		 */
        public function get windowMinWidth():Number{
            return this._windowMinWidth;
        }
        
        
		[Inspectable(defaultValue=50, verbose=1, category="Expanded Properties")]
        public function set windowMinHeight(value:Number):void{
            this._windowMinHeight= value;         
        }
        /**
		 * Définit la hauteur minimal de la fenêtre au redimensionnement.
		 * @param value:Number Heuteur mini de la fenêtre.
		 */
        public function get windowMinHeight():Number{
            return this._windowMinHeight;
        }
		
		
		[Inspectable(defaultValue=false, verbose=1, category="Expanded Properties")]
		public function set resizeEnabled(value:Boolean):void{
            this._resizeEnabled = value;         
        }
        /**
		 * Définit si le composant est redimensionnable. <br/>Si dragEnabled = true, les redimensionnements TOP, TOP_LEFT et TOP_RIGHT sont désactivés. 
		 * @param value:Boolean
		 */
        public function get resizeEnabled():Boolean{
            return this._resizeEnabled;
        }
		
		private static function initPosition(obj:Object):void{
			obj.oHeight = obj.height;
			obj.oWidth = obj.width;
			obj.oX = obj.x;
			obj.oY = obj.y;
		}
		
		private var _isResize:Boolean = false;
		
		// Set the first global point that mouse down on the window.
		// @param The MouseEvent.MOUSE_DOWN
		private function oMouseDown(event:MouseEvent):void{
			
			
			if(this.resizeEnabled == true) {
				parent.setChildIndex(this, parent.numChildren - 1);
				
				
				
				if(mouseState != SIDE_OTHER){
					
					dispatchEvent(new Event("startResizing"));
					// ------------------------------------------------------
					_isDrag = false;
					//_dragEnabled = dragEnabled == true ? false : _dragEnabled;
					// ------------------------------------------------------
					_isResize = true;
					resizeObj = event.currentTarget;
					//resizeObj = this;
					initPosition(resizeObj);
					oPoint.x = resizeObj.mouseX;
					oPoint.y = resizeObj.mouseY;
					oPoint = this.localToGlobal(oPoint);
				}
			
			}
		}
		
		// Show the mouse arrow when not draging.
		// Call oResize(event) to resize window when mouse is inside the window area.
		// @param The MouseEvent.MOUSE_MOVE
		private function oMouseMove(event:MouseEvent):void{
			
			if(resizeObj == null && this._resizeEnabled == true){
				
				var xPosition:Number = parent.mouseX;
				var yPosition:Number = parent.mouseY;
				
				// 
				if(xPosition >= (this.x + this.width - mouseMargin) && yPosition >= (this.y + this.height - mouseMargin)){
					CursorUtil.changeCursor(LEFT_OBLIQUE_CURSOR, -6, -6);
					mouseState = SIDE_RIGHT | SIDE_BOTTOM;
				}
				
				else if(!dragEnabled && xPosition <= (this.x + mouseMargin) && yPosition <= (this.y + mouseMargin)){
					CursorUtil.changeCursor(LEFT_OBLIQUE_CURSOR, -6, -6);
					mouseState = SIDE_LEFT | SIDE_TOP;
				}
				
				else if(xPosition <= (this.x + mouseMargin) && yPosition >= (this.y + this.height - mouseMargin)){
					CursorUtil.changeCursor(RIGHT_OBLIQUE_CURSOR, -6, -6);
					mouseState = SIDE_LEFT | SIDE_BOTTOM;
				}
				
				else if(!dragEnabled && xPosition >= (this.x + this.width - mouseMargin) && yPosition <= (this.y + mouseMargin)){
					CursorUtil.changeCursor(RIGHT_OBLIQUE_CURSOR, -6, -6);
					mouseState = SIDE_RIGHT | SIDE_TOP;
				}
				
				else if(!dragEnabled && xPosition >= (this.x + this.width - mouseMargin)){
					CursorUtil.changeCursor(HORIZONTAL_CURSOR, -9, -9);
					mouseState = SIDE_RIGHT;	
				}
				
				else if(xPosition >= (this.x + this.width - mouseMargin) && yPosition >= this.y+this.titleBar.height){
					CursorUtil.changeCursor(HORIZONTAL_CURSOR, -9, -9);
					mouseState = SIDE_RIGHT;	
				}
				
				else if(!dragEnabled && xPosition <= (this.x + mouseMargin)){
					CursorUtil.changeCursor(HORIZONTAL_CURSOR, -9, -9);
					mouseState = SIDE_LEFT;
				}
				
				else if(xPosition <= (this.x + mouseMargin) && yPosition >= this.y+this.titleBar.height){
					CursorUtil.changeCursor(HORIZONTAL_CURSOR, -9, -9);
					mouseState = SIDE_LEFT;
				}
			
				else if(yPosition >= (this.y + this.height - mouseMargin)){
					CursorUtil.changeCursor(VERTICAL_CURSOR, -9, -9);
					mouseState = SIDE_BOTTOM;
				}
				
				else if (!dragEnabled && yPosition <= (this.y + mouseMargin)) {
					CursorUtil.changeCursor(VERTICAL_CURSOR, -9, -9);
					mouseState = SIDE_TOP;
				}
				/*else if(yPosition <= (this.y + mouseMargin)){
					CursorUtil.changeCursor(VERTICAL_CURSOR, -9, -9);
					mouseState = SIDE_TOP;
				}*/
				
				else{
					mouseState = SIDE_OTHER;
					CursorUtil.changeCursor(null, 0, 0);
				}
			}
		}
		
		// Hide the arrow when not draging and moving out the window.
		// @param The MouseEvent.MOUSE_MOVE
		private function oMouseOut(event:MouseEvent):void{
			if(resizeObj == null && _resizeEnabled != false){
				dispatchEvent(new Event("stopResizing"));
				/// ------------------------------------------------------
				//_dragEnabled = dragEnabled == true ? true : _dragEnabled;
				// ------------------------------------------------------
				_isResize = false;
				CursorUtil.changeCursor(null, 0, 0);
			}
		}
		
		// Clear the resizeObj and also set the latest position.
		// @param The MouseEvent.MOUSE_UP
		private function oMouseUp(event:MouseEvent):void{
			if(resizeObj != null){
				initPosition(resizeObj);
			}
			resizeObj = null;
		}
		
		
		// Resize when the draging window, resizeObj is not null.
		// @param The MouseEvent.MOUSE_MOVE
		private function oResize(event:MouseEvent):void{
			if(resizeObj != null && this._resizeEnabled == true && _isResize == true && _isDrag == false){
				
				dispatchEvent(new Event("isResizing"));
				
				resizeObj.stopDragging();
				var xPlus:Number = Application.application.parent.mouseX - resizeObj.oPoint.x;
				var yPlus:Number = Application.application.parent.mouseY - resizeObj.oPoint.y;
				
			    switch(mouseState){	
			    	
			    	case SIDE_RIGHT | SIDE_BOTTOM:
			    		resizeObj.width = resizeObj.oWidth + xPlus > resizeObj._windowMinWidth ? resizeObj.oWidth + xPlus : resizeObj._windowMinWidth;
		    			resizeObj.height = resizeObj.oHeight + yPlus > resizeObj._windowMinHeight ? resizeObj.oHeight + yPlus : resizeObj._windowMinHeight;
			    		break;
			    	case SIDE_LEFT | SIDE_TOP:
		    			resizeObj.x = xPlus < resizeObj.oWidth - resizeObj._windowMinWidth ? resizeObj.oX + xPlus: resizeObj.x;
		    			resizeObj.y = yPlus < resizeObj.oHeight - resizeObj._windowMinHeight ? resizeObj.oY + yPlus : resizeObj.y;
			    		resizeObj.width = resizeObj.oWidth - xPlus > resizeObj._windowMinWidth ? resizeObj.oWidth - xPlus : resizeObj._windowMinWidth;
		    			resizeObj.height = resizeObj.oHeight - yPlus > resizeObj._windowMinHeight ? resizeObj.oHeight - yPlus : resizeObj._windowMinHeight;
			    		break;
			    	case SIDE_LEFT | SIDE_BOTTOM:
			    		resizeObj.x = xPlus < resizeObj.oWidth - resizeObj._windowMinWidth ? resizeObj.oX + xPlus: resizeObj.x;
			    		resizeObj.width = resizeObj.oWidth - xPlus > resizeObj._windowMinWidth ? resizeObj.oWidth - xPlus : resizeObj._windowMinWidth;
		    			resizeObj.height = resizeObj.oHeight + yPlus > resizeObj._windowMinHeight ? resizeObj.oHeight + yPlus : resizeObj._windowMinHeight;
			    		break;
			    	case SIDE_RIGHT | SIDE_TOP:
			    		resizeObj.y = yPlus < resizeObj.oHeight - resizeObj._windowMinHeight ? resizeObj.oY + yPlus : resizeObj.y;
			    		resizeObj.width = resizeObj.oWidth + xPlus > resizeObj._windowMinWidth ? resizeObj.oWidth + xPlus : resizeObj._windowMinWidth;
		    			resizeObj.height = resizeObj.oHeight - yPlus > resizeObj._windowMinHeight ? resizeObj.oHeight - yPlus : resizeObj._windowMinHeight;
			    		break;
			    	case SIDE_RIGHT:
			    		resizeObj.width = resizeObj.oWidth + xPlus > resizeObj._windowMinWidth ? resizeObj.oWidth + xPlus : resizeObj._windowMinWidth;
			    		break;
			    	case SIDE_LEFT:
			    		resizeObj.x = xPlus < resizeObj.oWidth - resizeObj._windowMinWidth ? resizeObj.oX + xPlus: resizeObj.x;
			    		resizeObj.width = resizeObj.oWidth - xPlus > resizeObj._windowMinWidth ? resizeObj.oWidth - xPlus : resizeObj._windowMinWidth;
			    		break;
			    	case SIDE_BOTTOM:
			    		resizeObj.height = resizeObj.oHeight + yPlus > resizeObj._windowMinHeight ? resizeObj.oHeight + yPlus : resizeObj.windowMinHeight;
			    		break;
			    	case SIDE_TOP:
			    		resizeObj.y = yPlus < resizeObj.oHeight - resizeObj._windowMinHeight ? resizeObj.oY + yPlus : resizeObj.y;
			    		resizeObj.height = resizeObj.oHeight - yPlus > resizeObj._windowMinHeight ? resizeObj.oHeight - yPlus : resizeObj._windowMinHeight;
			    		break;
			    }
			}
		}
		
		// GESTION STYLE 
		/**
		 * @private
		 */
    	override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			if (getStyle("cursorLeftObliqueSkin"))
				LEFT_OBLIQUE_CURSOR = getStyle("cursorLeftObliqueSkin");
			
			if (getStyle("cursorRightObliqueSkin"))
				RIGHT_OBLIQUE_CURSOR = getStyle("cursorRightObliqueSkin");
			
			if (getStyle("cursorHorizontalSkin"))
				HORIZONTAL_CURSOR = getStyle("cursorHorizontalSkin");
			
			if (getStyle("cursorVerticalSkin"))
				VERTICAL_CURSOR = getStyle("cursorVerticalSkin");
		}
	}
}